{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TVM 常用数据结构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `DLDeviceType`\n",
    "\n",
    "枚举类型 `DLDeviceType`，用于表示不同的设备类型。\n",
    "\n",
    "该枚举类型包含以下成员：\n",
    "- `kDLCPU`：表示 CPU 设备。\n",
    "- `kDLCUDA`：表示 CUDA GPU 设备。\n",
    "- `kDLCUDAHost`：表示通过 cudaMallocHost 固定分配的 CUDA CPU 内存。\n",
    "- `kDLOpenCL`：表示 OpenCL 设备。\n",
    "- `kDLVulkan`：表示下一代图形的 Vulkan 缓冲区。\n",
    "- `kDLMetal`：表示 Apple GPU 的 Metal。\n",
    "- `kDLVPI`：表示 Verilog 模拟器缓冲区。\n",
    "- `kDLROCM`：表示 AMD GPU 的 ROCm GPU。\n",
    "- `kDLExtDev`：保留的扩展设备类型，用于快速测试扩展设备。语义可能因实现而异。\n",
    "\n",
    "通过使用这个枚举类型，我们可以在程序中指定要使用的设备类型，以便根据不同的设备执行相应的操作或加载适当的库。\n",
    "\n",
    "## `DLDevice`\n",
    "\n",
    "结构体 `DLDevice`，用于表示一个设备，该设备可以处理张量和算子。\n",
    "\n",
    "该结构体包含以下成员：\n",
    "- `device_type`：设备中使用的设备类型，使用前面定义的枚举类型 `DLDeviceType` 表示。\n",
    "- `device_id`：设备的索引或标识符，使用整数类型 `int` 表示。\n",
    "\n",
    "通过使用这个结构体，我们可以创建一个表示特定设备的对象，并指定该设备的类型和索引。这样的对象可以用于在张量和运算符的处理中指定要使用的设备，以便执行相应的算子或加载适当的库。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `DLDataTypeCode`\n",
    "\n",
    "这段代码定义了一个枚举类型 `DLDataTypeCode`，用于表示不同的数据类型代码选项。\n",
    "\n",
    "该枚举类型包含以下成员：\n",
    "- `kDLInt`：有符号整数类型代码。\n",
    "- `kDLUInt`：无符号整数类型代码。\n",
    "- `kDLFloat`：IEEE浮点数类型代码。\n",
    "- `kDLOpaqueHandle`：不透明句柄类型代码，保留给测试目的使用。框架需要就交换的句柄数据类型达成一致，才能定义交换。\n",
    "- `kDLBfloat`：`bfloat16` 类型代码。\n",
    "- `kDLComplex`：复数类型代码（C/C++/Python布局：每个复数都有一个紧凑的结构体）。\n",
    "\n",
    "通过使用这个枚举类型，我们可以为不同的数据类型指定相应的类型代码。这样的代码可以用于在张量和运算符的处理中指定要使用的特定数据类型，以便执行相应的算子或加载适当的库。\n",
    "\n",
    "## `DLDataType`\n",
    "\n",
    "结构体 `DLDataType` 用于表示张量可以保存的数据类型：\n",
    "- `code`：基础类型的类型代码，使用 `uint8_t` 类型表示。为了最小化内存占用，我们使用 `uint8_t` 而不是 `DLDataTypeCode`，但值应该是 `DLDataTypeCode` 枚举值之一。\n",
    "- `bits`：位数，通常选择 8、16 和 32。\n",
    "- `lanes`：类型中的通道数，用于向量类型。\n",
    "\n",
    "使用这个结构体，可以表示不同的数据类型，并指定它们在内存中占用的位数和通道数。例如，对于浮点数类型，`type_code` 为 `2`，`bits` 为 `32`，`lanes` 为 `1`；对于向量化 4 个浮点数的类型，`type_code` 为 `2`，`bits` 为 `32`，`lanes` 为 `4`；对于 8 位整数类型，`type_code` 为 `0`，`bits` 为 `8`，`lanes` 为 `1`；对于 `std::complex<float>`，`type_code` 为 `5`，`bits` 为 `64`，`lanes` 为 `1`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `DLTensor`\n",
    "\n",
    "结构体 `DLTensor`，用于表示一个普通的 C 张量对象，该对象不管理内存。\n",
    "\n",
    "该结构体包含以下成员：\n",
    "- `data`：指向分配的数据的不透明数据指针。在 CUDA 中，这将是设备指针或 OpenCL 中的 `cl_mem` 句柄。此指针始终按 256 字节对齐，就像在 CUDA 中一样。给定的 DLTensor，存储数据内容所需的内存大小计算如下：\n",
    "  - `GetDataSize` 是一个静态内联函数，用于计算给定 DLTensor 所需的内存大小：\n",
    "  ```c\n",
    "    static inline size_t GetDataSize(const DLTensor* t) {\n",
    "        size_t size = 1;\n",
    "        for (tvm_index_t i = 0; i < t->ndim; ++i) {\n",
    "            size *= t->shape[i];\n",
    "        }\n",
    "        size *= (t->dtype.bits * t->dtype.lanes + 7) / 8;\n",
    "        return size;\n",
    "    }\n",
    "  ```\n",
    "- `device`：张量的设备类型，使用前面定义的枚举类型 `DLDevice` 表示。\n",
    "- `ndim`：张量的维数。\n",
    "- `dtype`：指针的数据类型，使用前面定义的枚举类型 `DLDataType` 表示。\n",
    "- `shape`：张量的形状，使用指向整数的指针表示。\n",
    "- `strides`：张量的步幅（以元素数量而不是字节为单位），可以为 `NULL`，表示张量紧凑且采用行优先方式。\n",
    "- `byte_offset`：指向数据的起始指针的字节偏移量。\n",
    "\n",
    "通过使用这个结构体，我们可以创建表示特定张量的对象，并指定该张量的数据、设备类型、维数、数据类型、形状和步幅等信息。这样的对象可以用于在张量处理中执行相应的算子或加载适当的库。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `DLManagedTensor`\n",
    "\n",
    "结构体 `DLManagedTensor`，用于表示托管张量对象。该结构体管理 `DLTensor` 的内存，并提供了在另一个框架中借用张量的便利性。它并不转移张量，当借用框架不再需要张量时，应调用删除器通知主机资源不再需要。\n",
    "\n",
    "该结构体包含以下成员：\n",
    "- `dl_tensor`：正在被内存管理的 `DLTensor`。\n",
    "- `manager_ctx`：`DLManagedTensor` 使用的原始主机框架的上下文。如果 `DLManagedTensor` 在框架中使用，则可以为 `NULL`。\n",
    "- `deleter`：用于销毁 `manager_ctx` 的析构函数签名。应调用此函数以销毁持有 `DLManagedTensor` 的 `manager_ctx`。如果调用者无法提供合理的析构函数，则可以将其设置为 `NULL`。析构函数将删除参数 `self`。\n",
    "\n",
    "通过使用这个结构体，我们可以创建一个托管张量对象，并指定该张量的数据、原始主机框架的上下文以及用于销毁 `manager_ctx` 的析构函数。这样的对象可以在框架之间方便地借用和管理张量，以便进行相应的操作或加载适当的库。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `TVMValue`\n",
    "\n",
    "联合类型（union type）`TVMValue` 允许在同一内存位置存储不同的数据类型，但一次只能存储其中一种类型的值：\n",
    "- `v_int64`：64 位整数（`int64_t`）类型。\n",
    "- `v_float64`：64 位浮点数（`double`）类型。\n",
    "- `v_handle`：指向句柄（handle）的指针类型，用于引用各种对象或资源。\n",
    "- `v_str`：指向字符串的指针类型，用于表示文本数据。\n",
    "- `v_type`：`DLDataType` 类型，表示数据类型。\n",
    "- `v_device`：`DLDevice`类型，表示设备信息。\n",
    "\n",
    "通过使用这个联合类型，可以在 API 和函数调用中传递不同类型的值，而无需显式地进行类型转换。根据需要，可以将 `TVMValue` 实例中的特定成员赋值为相应的值，并使用该实例来传递数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `TVMArgs`\n",
    "\n",
    "结构体 `TVMArgs`，用于表示 TVM 函数的参数。\n",
    "\n",
    "该结构体包含以下成员：\n",
    "- `values`：一个长度为 `TVM_CRT_MAX_ARGS` 的 `TVMValue` 数组，用于存储函数的参数值。\n",
    "- `tcodes`：一个长度为 `TVM_CRT_MAX_ARGS` 的整数数组，用于存储函数参数的数据类型码。数据类型应与 `TVMPackedCFunc` 中的 `type_codes` 相同。\n",
    "- `values_count`：一个无符号 32 位整数，表示 `values` 数组中的元素数量。\n",
    "\n",
    "通过使用这个结构体，我们可以创建表示 TVM 函数参数的对象，并指定该函数的参数值、数据类型码和参数数量。这样的对象可以用于在 TVM 编译过程中传递参数给函数，以便进行相应的算子或加载适当的库。"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
